www.gusucode.com > VC++ 编写软件自动升级服务源代码 > VC++ 编写软件自动升级服务源代码/gusucode/updater_src0.8.1.6/CustomBitmapButton.cpp

    /**********************************************************************
**
**	CustomBitmapButton.cpp : implementation file of the
**								CCustomBitmapButton class
**
**	by Andrzej Markowski August 2004
**
**********************************************************************/

#include "stdafx.h"
#include "CustomBitmapButton.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCustomBitmapButton

CMap <HWND,HWND,CCustomBitmapButton*,CCustomBitmapButton*> CCustomBitmapButton::m_mapCaptionFrames;
CCriticalSection CCustomBitmapButton::m_cs;

CCustomBitmapButton::CCustomBitmapButton() :
		m_nBkStyle(CBNBKGNDSTYLE_CAPTION),
		m_fActive(TRUE),
		m_nState(CBNST_NORMAL),
		m_nHeldNdx(-1),
		m_bHeld(HELDNONE),
		m_nOverNdx(-1),
		m_hBmpBk(NULL),
		m_hBmpGlyph(NULL),
		m_pOldWndProc(NULL),
		m_pCaptionWnd(NULL)
{
	RegisterWindowClass();
}

CCustomBitmapButton::~CCustomBitmapButton()
{
	::DeleteObject(m_hBmpBk);
	m_hBmpBk = NULL;
	::DeleteObject(m_hBmpGlyph);
	m_hBmpGlyph = NULL;
}

BEGIN_MESSAGE_MAP(CCustomBitmapButton, CWnd)
	//{{AFX_MSG_MAP(CCustomBitmapButton)
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_RBUTTONUP()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)
	ON_MESSAGE(WM_THEMECHANGED,OnThemeChanged)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCustomBitmapButton message handlers

BOOL CCustomBitmapButton::RegisterWindowClass()
{
    WNDCLASS wndcls;
    HINSTANCE hInst = AfxGetInstanceHandle();

    if (!(::GetClassInfo(hInst, CustomBitmapButton_CLASSNAME, &wndcls)))
    {
        wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
        wndcls.lpfnWndProc      = ::DefWindowProc;
        wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
        wndcls.hInstance        = hInst;
        wndcls.hIcon            = NULL;
        wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
        wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);
        wndcls.lpszMenuName     = NULL;
        wndcls.lpszClassName    = CustomBitmapButton_CLASSNAME;

        if (!AfxRegisterClass(&wndcls))
        {
            AfxThrowResourceException();
            return FALSE;
        }
    }

    return TRUE;
}

BOOL CCustomBitmapButton::Create(UINT dwStyle, const CRect & rect, CWnd * pParentWnd, UINT nID)
{
	return CWnd::Create(CustomBitmapButton_CLASSNAME, _T(""), dwStyle, rect, pParentWnd, nID);
}

int CCustomBitmapButton::CreateCaptionFrame(CWnd * pCaptionWnd, int nIDIcon)
{
	if(m_hWnd)
		return CBNERR_INCORRECTFUNCCALL;
	
	if(pCaptionWnd==NULL || pCaptionWnd->m_hWnd==NULL)
		return CBNERR_INCORRECTPARAMETER;
	
	if(m_pOldWndProc)
		return CBNERR_FRAMEALREADYCREATED;
	
	LONG dwStyle = pCaptionWnd->GetStyle();
	if(!(dwStyle & WS_CAPTION))
		return CBNERR_INCORRECTFRAMESTYLE;

	CCustomBitmapButton* p;
	m_cs.Lock();
	if(m_mapCaptionFrames.Lookup(pCaptionWnd->m_hWnd,p))
	{
		m_cs.Unlock();
		return CBNERR_INCORRECTPARAMETER;
	}
	if(!(m_pOldWndProc = (WNDPROC)::SetWindowLong(pCaptionWnd->m_hWnd, GWL_WNDPROC, (DWORD)CaptionFrameWindowProc)))
	{
		m_cs.Unlock();
		return CBNERR_SETWINDOWLONGFAILED;
	}
	m_mapCaptionFrames.SetAt(pCaptionWnd->m_hWnd,this);
	m_pCaptionWnd = pCaptionWnd;
	m_cs.Unlock();

	m_nIDIcon = nIDIcon;

	int nRet;
	// Close button
	if((nRet=AddCaptionButton(CRect(0,0,0,0),0,CBNBKGNDSTYLE_CLOSE,FALSE)))
	{
		DestroyCaptionFrame();
		return nRet;
	}
	// Maximize button
	if((nRet=AddCaptionButton(CRect(0,0,0,0),0,CBNBKGNDSTYLE_CAPTION,FALSE)))
	{
		DestroyCaptionFrame();
		return nRet;
	}
	// Minimize button
	if((nRet=AddCaptionButton(CRect(0,0,0,0),0,CBNBKGNDSTYLE_CAPTION,FALSE)))
	{
		DestroyCaptionFrame();
		return nRet;
	}
	// Help button
	if((nRet=AddCaptionButton(CRect(0,0,0,0),0,CBNBKGNDSTYLE_CAPTION,FALSE)))
	{
		DestroyCaptionFrame();
		return nRet;
	}
	m_Theme.CloseThemeData();
	m_Theme.OpenThemeData(pCaptionWnd->m_hWnd,L"WINDOW");
	return CBNERR_NOERROR;
}

int CCustomBitmapButton::DestroyCaptionFrame()
{
	if(!m_pOldWndProc)
		return CBNERR_NOERROR;
	m_cs.Lock();
	if(!((WNDPROC)::SetWindowLong(m_pCaptionWnd->m_hWnd, GWL_WNDPROC, (DWORD)m_pOldWndProc)))
	{
		m_cs.Unlock();
		return CBNERR_SETWINDOWLONGFAILED;
	}
	m_mapCaptionFrames.RemoveKey(m_pCaptionWnd->m_hWnd);
	m_pOldWndProc = NULL;
	m_pCaptionWnd = NULL;
	m_cs.Unlock();

	for(int i=0;i<m_aButtons.GetSize();i++)
	{
		CCustomBitmapButton* pBn = m_aButtons[i];
		pBn->DestroyWindow();
		delete pBn;
	}
	m_aButtons.RemoveAll();
	m_Theme.CloseThemeData();
	return CBNERR_NOERROR;
}

int CCustomBitmapButton::AddCaptionButton(LPCRECT lpRect, UINT nID, int nBkStyle, BOOL fUserDefWidth)
{
	if(!m_pOldWndProc)
		return CBNERR_FRAMENOTCREATED;
	CCustomBitmapButton* pBn = new CCustomBitmapButton();
	if(pBn==NULL)
		return CBNERR_OUTOFMEMORY;
	pBn->m_rect = *lpRect;
	if(nBkStyle>=CBNBKGNDSTYLE_CAPTION && nBkStyle<=CBNBKGNDSTYLE_SPINDNHOR)
		pBn->m_nBkStyle = nBkStyle;
	else
	{
		delete pBn;
		return CBNERR_INCORRECTPARAMETER;
	}
	
	DWORD dwStyle = WS_CHILD|CBNSTYLE_CAPTION;
	if(fUserDefWidth)
		dwStyle |= CBNSTYLE_USERDEFWIDTH;

	if(!pBn->Create(dwStyle,lpRect,m_pCaptionWnd,nID))
	{
		delete pBn;
		return CBNERR_CREATEBUTTONFAILED;
	}
	pBn->m_pCaptionWnd = m_pCaptionWnd;
	int ndx = m_aButtons.Add(pBn);

	if(ndx>=4)
	{
		CRect r;
		m_pCaptionWnd->GetWindowRect(r);
		m_pCaptionWnd->MoveWindow(r);
	}
	return CBNERR_NOERROR;
}

int CCustomBitmapButton::SetTooltipText(CString sText)
{
	if(m_pOldWndProc)
		return CBNERR_INCORRECTFUNCCALL;
	CWnd* pTooltipWnd;
	CCustomBitmapButton* pTooltipBn;
	CRect r;
	if(GetStyle()&CBNSTYLE_CAPTION)
	{
		if(m_pCaptionWnd==NULL)
			return CBNERR_INCORRECTBUTTONSTYLE;
		pTooltipWnd = m_pCaptionWnd;
		m_cs.Lock();
		if(!m_mapCaptionFrames.Lookup(m_pCaptionWnd->m_hWnd,pTooltipBn))
		{
			m_cs.Unlock();
			return CBNERR_INCORRECTBUTTONSTYLE;
		}
		m_cs.Unlock();
		r = m_rect;
		r.SetRect(0,0,0,0);
	}
	else
	{
		pTooltipWnd = this;
		pTooltipBn = this;
		GetClientRect(r);
	}
	if(pTooltipBn->m_ctrlToolTip.m_hWnd==NULL)
	{
		if(!pTooltipBn->m_ctrlToolTip.Create(pTooltipWnd))
			return CBNERR_CREATETOOLTIPCTRLFAILED;
		pTooltipBn->m_ctrlToolTip.Activate(TRUE);
	}
	pTooltipBn->m_ctrlToolTip.DelTool(pTooltipWnd,GetDlgCtrlID());
	pTooltipBn->m_ctrlToolTip.AddTool(pTooltipWnd,sText,r,GetDlgCtrlID());
	return CBNERR_NOERROR;
}

int CCustomBitmapButton::SetBkStyle(int nBkStyle)
{
	if(m_pOldWndProc)
		return CBNERR_INCORRECTFUNCCALL;
	if(GetStyle()&CBNSTYLE_CAPTION && m_pCaptionWnd==NULL)
		return CBNERR_INCORRECTBUTTONSTYLE;

	if(nBkStyle>=CBNBKGNDSTYLE_CAPTION && nBkStyle<=CBNBKGNDSTYLE_SCROLLRIGHT)
	{
		m_nBkStyle = nBkStyle;
		OnThemeChanged(0,0);
		if(GetStyle()&CBNSTYLE_CAPTION)
			m_pCaptionWnd->RedrawWindow(m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
		else
			Invalidate();
		return CBNERR_NOERROR;
	}
	return CBNERR_INCORRECTPARAMETER;
}

int CCustomBitmapButton::SetGlyphBitmap(HBITMAP hBmpGlyph)
{
	if(m_pOldWndProc)
		return CBNERR_INCORRECTFUNCCALL;
	if(GetStyle()&CBNSTYLE_CAPTION && m_pCaptionWnd==NULL)
		return CBNERR_INCORRECTBUTTONSTYLE;

	::DeleteObject(m_hBmpGlyph);
	m_hBmpGlyph = NULL;
	if(hBmpGlyph==NULL)
	{
		if(GetStyle()&CBNSTYLE_CAPTION)
			m_pCaptionWnd->RedrawWindow(m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
		else
			Invalidate();
		return CBNERR_NOERROR;
	}
	
	BITMAP bm;
	CBitmap::FromHandle(hBmpGlyph)->GetBitmap(&bm);
	m_hBmpGlyph = (HBITMAP)::CopyImage(hBmpGlyph,IMAGE_BITMAP,bm.bmWidth,bm.bmHeight,LR_MONOCHROME);
	if(m_hBmpGlyph==NULL)
		return CBNERR_COPYIMAGEFAILED;

	if(GetStyle()&CBNSTYLE_CAPTION)
		m_pCaptionWnd->RedrawWindow(m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
	else
		Invalidate();
	return CBNERR_NOERROR;
}

int CCustomBitmapButton::EnableWindow(BOOL fEnable)
{
	if(m_pOldWndProc)
		return CBNERR_INCORRECTFUNCCALL;
	if(GetStyle()&CBNSTYLE_CAPTION && m_pCaptionWnd==NULL)
		return CBNERR_INCORRECTBUTTONSTYLE;
	CWnd::EnableWindow(fEnable);
	if(GetStyle()&CBNSTYLE_CAPTION)
		m_pCaptionWnd->RedrawWindow(m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
	else
		Invalidate();
	return CBNERR_NOERROR;
}

BOOL CCustomBitmapButton::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
}

void CCustomBitmapButton::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	Draw(dc);	
}

void CCustomBitmapButton::DrawBk(CDC& dc, CRect& r, int nImageNdx)
{
	MY_MARGINS m = {m_mrgnBk.cxLeftWidth,m_mrgnBk.cxRightWidth,m_mrgnBk.cyBottomHeight,m_mrgnBk.cyTopHeight};
	
	if((m.cxLeftWidth+m.cxRightWidth>r.Width()) || (m.cyTopHeight+m.cyBottomHeight>r.Height()))
		return;	// the rectangle too small

	if(2*(m.cxLeftWidth+m.cxRightWidth)>r.Width())
	{
		int nDelta = r.Width() - (m.cxLeftWidth+m.cxRightWidth);
		m.cxLeftWidth += nDelta/2;
		m.cxRightWidth += nDelta/2 + nDelta%2;
	}

	if(2*(m.cyTopHeight+m.cyBottomHeight)>r.Height())
	{
		int nDelta = r.Height() - (m.cyTopHeight+m.cyBottomHeight);
		m.cyTopHeight += nDelta/2;
		m.cyBottomHeight += nDelta/2 + nDelta%2;
	}

	CDC dcMem;
	dcMem.CreateCompatibleDC(&dc);
	CBitmap* pBmp = CBitmap::FromHandle(m_hBmpBk);
	BITMAP bm;
	pBmp->GetBitmap(&bm);
	CBitmap* pOldBmp = dcMem.SelectObject(pBmp);
	if(m_fBkImageHorLayout)
	{
		// left-top
		dc.BitBlt(r.left,
				r.top,
				m.cxLeftWidth,
				m.cyTopHeight,
				&dcMem,
				nImageNdx*bm.bmWidth/m_nImageCount,
				0,
				SRCCOPY);
		
		// right-top
		dc.BitBlt(r.right-m.cxRightWidth,
				r.top,
				m.cxRightWidth,
				m.cyTopHeight,
				&dcMem,
				(nImageNdx+1)*bm.bmWidth/m_nImageCount-m.cxRightWidth,
				0,
				SRCCOPY);

		// left-bottom
		dc.BitBlt(r.left,
				r.bottom-m.cyBottomHeight,
				m.cxLeftWidth,
				m.cyBottomHeight,
				&dcMem,
				nImageNdx*bm.bmWidth/m_nImageCount,
				bm.bmHeight-m.cyBottomHeight,
				SRCCOPY);

		// right-bottom
		dc.BitBlt(r.right-m.cxRightWidth,
				r.bottom-m.cyBottomHeight,
				m.cxRightWidth,
				m.cyBottomHeight,
				&dcMem,
				(nImageNdx+1)*bm.bmWidth/m_nImageCount-m.cxRightWidth,
				bm.bmHeight-m.cyBottomHeight,
				SRCCOPY);

		// middle-top
		dc.StretchBlt(r.left+m.cxLeftWidth,
			r.top,
			r.Width()-m.cxLeftWidth-m.cxRightWidth,
			m.cyTopHeight,
			&dcMem,
			nImageNdx*bm.bmWidth/m_nImageCount+m.cxLeftWidth,
			0,
			bm.bmWidth/m_nImageCount-m.cxLeftWidth-m.cxRightWidth,
			m.cyTopHeight,
			SRCCOPY);

		// middle-bottom
		dc.StretchBlt(r.left+m.cxLeftWidth,
			r.bottom-m.cyBottomHeight,
			r.Width()-m.cxLeftWidth-m.cxRightWidth,
			m.cyBottomHeight,
			&dcMem,
			nImageNdx*bm.bmWidth/m_nImageCount+m.cxLeftWidth,
			bm.bmHeight-m.cyBottomHeight,
			bm.bmWidth/m_nImageCount-m.cxLeftWidth-m.cxRightWidth,
			m.cyBottomHeight,
			SRCCOPY);

		// middle-left
		dc.StretchBlt(r.left,
			r.top+m.cyTopHeight,
			m.cxLeftWidth,
			r.Height()-m.cyTopHeight-m.cyBottomHeight,
			&dcMem,
			nImageNdx*bm.bmWidth/m_nImageCount,
			m.cyTopHeight,
			m.cxLeftWidth,
			bm.bmHeight-m.cyTopHeight-m.cyBottomHeight,
			SRCCOPY);

		// middle-right
		dc.StretchBlt(r.right-m.cxRightWidth,
			r.top+m.cyTopHeight,
			m.cxRightWidth,
			r.Height()-m.cyTopHeight-m.cyBottomHeight,
			&dcMem,
			(nImageNdx+1)*bm.bmWidth/m_nImageCount-m.cxRightWidth,
			m.cyTopHeight,
			m.cxRightWidth,
			bm.bmHeight-m.cyTopHeight-m.cyBottomHeight,
			SRCCOPY);

		// middle
		dc.StretchBlt(
			r.left+m.cxLeftWidth,
			r.top+m.cyTopHeight,
			r.Width()-m.cxLeftWidth-m.cxRightWidth,
			r.Height()-m.cyTopHeight-m.cyBottomHeight,
			&dcMem,
			nImageNdx*bm.bmWidth/m_nImageCount + m.cxLeftWidth,
			m.cyTopHeight,
			bm.bmWidth/m_nImageCount-m.cxLeftWidth-m.cxRightWidth,
			bm.bmHeight-m.cyTopHeight-m.cyBottomHeight,
			SRCCOPY);
	}
	else
	{
		// left-top
		dc.BitBlt(r.left,
				r.top,
				m.cxLeftWidth,
				m.cyTopHeight,
				&dcMem,
				0,
				nImageNdx*bm.bmHeight/m_nImageCount,
				SRCCOPY);
		
		// right-top
		dc.BitBlt(r.right-m.cxRightWidth,
				r.top,
				m.cxRightWidth,
				m.cyTopHeight,
				&dcMem,
				bm.bmWidth-m.cxRightWidth,
				nImageNdx*bm.bmHeight/m_nImageCount,
				SRCCOPY);
		
		// left-bottom
		dc.BitBlt(r.left,
				r.bottom-m.cyBottomHeight,
				m.cxLeftWidth,
				m.cyBottomHeight,
				&dcMem,
				0,
				(nImageNdx+1)*bm.bmHeight/m_nImageCount-m.cyBottomHeight,
				SRCCOPY);

		// right-bottom
		dc.BitBlt(r.right-m.cxRightWidth,
				r.bottom-m.cyBottomHeight,
				m.cxRightWidth,
				m.cyBottomHeight,
				&dcMem,
				bm.bmWidth-m.cxRightWidth,
				(nImageNdx+1)*bm.bmHeight/m_nImageCount-m.cyBottomHeight,
				SRCCOPY);

		// middle-top
		dc.StretchBlt(r.left+m.cxLeftWidth,
			r.top,
			r.Width()-m.cxLeftWidth-m.cxRightWidth,
			m.cyTopHeight,
			&dcMem,
			m.cxLeftWidth,
			nImageNdx*bm.bmHeight/m_nImageCount,
			bm.bmWidth-m.cxLeftWidth-m.cxRightWidth,
			m.cyTopHeight,
			SRCCOPY);

		// middle-bottom
		dc.StretchBlt(r.left+m.cxLeftWidth,
			r.bottom-m.cyBottomHeight,
			r.Width()-m.cxLeftWidth-m.cxRightWidth,
			m.cyBottomHeight,
			&dcMem,
			m.cxLeftWidth,
			(nImageNdx+1)*bm.bmHeight/m_nImageCount-m.cyBottomHeight,
			bm.bmWidth-m.cxLeftWidth-m.cxRightWidth,
			m.cyBottomHeight,
			SRCCOPY);

		// middle-left
		dc.StretchBlt(r.left,
			r.top+m.cyTopHeight,
			m.cxLeftWidth,
			r.Height()-m.cyTopHeight-m.cyBottomHeight,
			&dcMem,
			0,
			nImageNdx*bm.bmHeight/m_nImageCount+m.cyTopHeight,
			m.cxLeftWidth,
			bm.bmHeight/m_nImageCount-m.cyTopHeight-m.cyBottomHeight,
			SRCCOPY);

		// middle-right
		dc.StretchBlt(r.right-m.cxRightWidth,
			r.top+m.cyTopHeight,
			m.cxRightWidth,
			r.Height()-m.cyTopHeight-m.cyBottomHeight,
			&dcMem,
			bm.bmWidth-m.cxRightWidth,
			nImageNdx*bm.bmHeight/m_nImageCount+m.cyTopHeight,
			m.cxRightWidth,
			bm.bmHeight/m_nImageCount-m.cyTopHeight-m.cyBottomHeight,
			SRCCOPY);

		// middle
		dc.StretchBlt(
			r.left+m.cxLeftWidth,
			r.top+m.cyTopHeight,
			r.Width()-m.cxLeftWidth-m.cxRightWidth,
			r.Height()-m.cyTopHeight-m.cyBottomHeight,
			&dcMem,
			m.cxLeftWidth,
			nImageNdx*bm.bmHeight/m_nImageCount+m.cyTopHeight,
			bm.bmWidth-m.cxLeftWidth-m.cxRightWidth,
			bm.bmHeight/m_nImageCount-m.cyTopHeight-m.cyBottomHeight,
			SRCCOPY);
	}
	dcMem.SelectObject(pOldBmp);
}

void CCustomBitmapButton::DrawGlyph(CDC& dc, CRect& r, int nColorNdx)
{
	if(m_hBmpGlyph==NULL)
		return;
	
	BITMAP bm;
	CBitmap::FromHandle(m_hBmpGlyph)->GetBitmap(&bm);
	CPoint pt(r.left+(r.Width()-bm.bmWidth)/2,r.top+(r.Height()-bm.bmHeight)/2);
	
	CDC dcMem, dcMemMono;
	dcMem.CreateCompatibleDC(&dc);
	dcMemMono.CreateCompatibleDC(&dc);

	CBitmap* pOldBmpGlyphMono = dcMemMono.SelectObject(CBitmap::FromHandle(m_hBmpGlyph));

	CBitmap bmpGlyphColor;
	bmpGlyphColor.CreateCompatibleBitmap(&dc,bm.bmWidth,bm.bmHeight);
	
	CBitmap* pOldBmpGlyphColor = dcMem.SelectObject(&bmpGlyphColor);

	COLORREF rgbOldTextGlyph = dcMem.SetTextColor(m_rgbGlyph[nColorNdx]);
	dcMem.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcMemMono, 0, 0, SRCCOPY);
	dcMem.SetTextColor(rgbOldTextGlyph);

	COLORREF rgbOldBk = dc.SetBkColor(RGB(255,255,255));
	COLORREF rgbOldText = dc.SetTextColor(RGB(0,0,0));
	dc.BitBlt(pt.x, pt.y, bm.bmWidth, bm.bmHeight, &dcMem, 0, 0, SRCINVERT);
	dc.BitBlt(pt.x, pt.y, bm.bmWidth, bm.bmHeight, &dcMemMono, 0, 0, SRCAND);
	dc.BitBlt(pt.x, pt.y, bm.bmWidth, bm.bmHeight, &dcMem, 0, 0, SRCINVERT);

	dcMem.SelectObject(pOldBmpGlyphColor);
	dcMemMono.SelectObject(pOldBmpGlyphMono);
	dc.SetBkColor(rgbOldBk);
	dc.SetTextColor(rgbOldText);
}

void CCustomBitmapButton::GetGlyphColorHor(int i, int iMin, int iMax, int ndx, COLORGLYPH& st)
{
	if(i==iMin)
	{
		for(int k=0; k<4; k++)
		{
			st.a[k].rgbGlyph = st.rgbTransGlyph;
			st.a[k].nCnt = 0;
		}
	}
	for(int j=0;j<st.nHeight;j++)
	{
		if(st.pDC->GetPixel(i,j)!=st.rgbTransGlyph)
		{
			for(int k=0; k<4; k++)
			{
				if(st.a[k].nCnt==0)
				{
					st.a[k].rgbGlyph = st.pDC->GetPixel(i,j);
					st.a[k].nCnt = 1;
					break;
				}
				else if(st.a[k].rgbGlyph == st.pDC->GetPixel(i,j))
				{
					st.a[k].nCnt++;
					break;
				}
			}	
		}
	}
	if(i==iMax-1)
	{
		if(st.a[0].nCnt==0)
			AfxThrowUserException();
		int nMaxCnt = 0;
		int nMaxNdx=0;
		for(int k=0; k<4; k++)
		{
			if(st.a[k].nCnt>nMaxCnt)
			{
				nMaxCnt = st.a[k].nCnt;
				nMaxNdx = k;
			}
		}
		m_rgbGlyph[ndx] = st.a[nMaxNdx].rgbGlyph;
	}
}

void CCustomBitmapButton::GetGlyphColorVer(int i, int iMin, int iMax, int ndx, COLORGLYPH& st)
{
	if(i==iMin)
	{
		for(int k=0; k<4; k++)
		{
			st.a[k].rgbGlyph = st.rgbTransGlyph;
			st.a[k].nCnt = 0;
		}
	}
	for(int j=0;j<st.nWidth;j++)
	{
		if(st.pDC->GetPixel(j,i)!=st.rgbTransGlyph)
		{
			for(int k=0; k<4; k++)
			{
				if(st.a[k].nCnt==0)
				{
					st.a[k].rgbGlyph = st.pDC->GetPixel(j,i);
					st.a[k].nCnt = 1;
					break;
				}
				else if(st.a[k].rgbGlyph == st.pDC->GetPixel(j,i))
				{
					st.a[k].nCnt++;
					break;
				}
			}	
		}
	}
	if(i==iMax-1)
	{
		if(st.a[0].nCnt==0)
			AfxThrowUserException();
		int nMaxCnt = 0;
		int nMaxNdx=0;
		for(int k=0; k<4; k++)
		{
			if(st.a[k].nCnt>nMaxCnt)
			{
				nMaxCnt = st.a[k].nCnt;
				nMaxNdx = k;
			}
		}
		m_rgbGlyph[ndx] = st.a[nMaxNdx].rgbGlyph;
	}
}

LONG CCustomBitmapButton::OnThemeChanged(WPARAM wParam, LPARAM lParam) 
{
	::DeleteObject(m_hBmpBk);
	m_hBmpBk = NULL;
	
	m_Theme.CloseThemeData();

	int nPartID;
	int nGlyphPropID;
	WCHAR sClass[50];
	switch(m_nBkStyle)
	{
	case CBNBKGNDSTYLE_CAPTION:
		m_nImageCount = 8;
		m_nImageOffset = 0;
		nPartID = WP_MAXBUTTON;
		nGlyphPropID = TMT_IMAGEFILE1;
		wcscpy(sClass,L"WINDOW");
		break;
	case CBNBKGNDSTYLE_CLOSE:
		m_nImageCount = 8;
		m_nImageOffset = 0;
		nPartID = WP_CLOSEBUTTON;
		nGlyphPropID = TMT_IMAGEFILE1;
		wcscpy(sClass,L"WINDOW");
		break;
	case CBNBKGNDSTYLE_MDI: 
		m_nImageCount = 4;
		m_nImageOffset = 0;
		nPartID = WP_MDIMINBUTTON;
		nGlyphPropID = TMT_GLYPHIMAGEFILE;
		wcscpy(sClass,L"WINDOW");
		break;
	case CBNBKGNDSTYLE_COMBO: 
		m_nImageCount = 4;
		m_nImageOffset = 0;
		nPartID = CP_DROPDOWNBUTTON;
		nGlyphPropID = TMT_GLYPHIMAGEFILE;
		wcscpy(sClass,L"COMBOBOX");
		break;
	case CBNBKGNDSTYLE_SPINUP: 
		m_nImageCount = 4;
		m_nImageOffset = 0;
		nPartID = SPNP_UP;
		nGlyphPropID = TMT_GLYPHIMAGEFILE;
		wcscpy(sClass,L"SPIN");
		break;
	case CBNBKGNDSTYLE_SPINDN: 
		m_nImageCount = 4;
		m_nImageOffset = 0;
		nPartID = SPNP_DOWN;
		nGlyphPropID = TMT_GLYPHIMAGEFILE;
		wcscpy(sClass,L"SPIN");
		break;
	case CBNBKGNDSTYLE_SPINUPHOR: 
		m_nImageCount = 4;
		m_nImageOffset = 0;
		nPartID = SPNP_UPHORZ;
		nGlyphPropID = TMT_GLYPHIMAGEFILE;
		wcscpy(sClass,L"SPIN");
		break;
	case CBNBKGNDSTYLE_SPINDNHOR: 
		m_nImageCount = 4;
		m_nImageOffset = 0;
		nPartID = SPNP_DOWNHORZ;
		nGlyphPropID = TMT_GLYPHIMAGEFILE;
		wcscpy(sClass,L"SPIN");
		break;
	case CBNBKGNDSTYLE_SCROLLUP: 
		m_nImageCount = 16;
		m_nImageOffset = 0;
		nPartID = SBP_ARROWBTN;
		nGlyphPropID = TMT_IMAGEFILE1;
		wcscpy(sClass,L"SCROLLBAR");
		break;
	case CBNBKGNDSTYLE_SCROLLDOWN: 
		m_nImageCount = 16;
		m_nImageOffset = 4;
		nPartID = SBP_ARROWBTN;
		nGlyphPropID = TMT_IMAGEFILE1;
		wcscpy(sClass,L"SCROLLBAR");
		break;
	case CBNBKGNDSTYLE_SCROLLLEFT: 
		m_nImageCount = 16;
		m_nImageOffset = 8;
		nPartID = SBP_ARROWBTN;
		nGlyphPropID = TMT_IMAGEFILE1;
		wcscpy(sClass,L"SCROLLBAR");
		break;
	case CBNBKGNDSTYLE_SCROLLRIGHT: 
		m_nImageCount = 16;
		m_nImageOffset = 12;
		nPartID = SBP_ARROWBTN;
		nGlyphPropID = TMT_IMAGEFILE1;
		wcscpy(sClass,L"SCROLLBAR");
		break;
	default:
		return 0;
		break;
	}

	HBITMAP hBmpGlyph = NULL;
	CDC dcGlyph;
	dcGlyph.CreateCompatibleDC(NULL);
	CBitmap* pOldBmpGlyph = NULL;

	try
	{
		if(!m_Theme.OpenThemeData(m_hWnd, sClass))
			AfxThrowUserException();

		{
			// background
			int nBkType;
			if(!m_Theme.GetThemeEnumValue(nPartID,0,TMT_BGTYPE,&nBkType))
				AfxThrowUserException();
			if(nBkType!=BT_IMAGEFILE)
				AfxThrowUserException();

			int nImageCount;
			if(!m_Theme.GetThemeInt(nPartID,0,TMT_IMAGECOUNT,&nImageCount))
				AfxThrowUserException();
			if(nImageCount!=m_nImageCount)
				AfxThrowUserException();

			WCHAR szBkBitmapFilename[MAX_PATH];
			if(!m_Theme.GetThemeFilename(nPartID,0,TMT_IMAGEFILE,szBkBitmapFilename,MAX_PATH))
				AfxThrowUserException();
			CString sFile(szBkBitmapFilename);
			if(!(m_hBmpBk = m_Theme.LoadBitmap(szBkBitmapFilename)))
				AfxThrowUserException();

			int nRet = m_Theme.IsThemeBackgroundPartiallyTransparent(nPartID,0);
			if(nRet==-1)
				AfxThrowUserException();
			m_fBkTransparent = nRet;
			if(nRet)
			{
				m_rgbBkTransparent = RGB(255,0,255);
				if(!m_Theme.GetThemeColor(nPartID,0,TMT_TRANSPARENTCOLOR,&m_rgbBkTransparent))
					AfxThrowUserException();
			}
			
			int nImageLayout;
			if(!m_Theme.GetThemeEnumValue(nPartID,0,TMT_IMAGELAYOUT,&nImageLayout))
				AfxThrowUserException();
			if(nImageLayout==IL_VERTICAL)
				m_fBkImageHorLayout = FALSE;
			else
				m_fBkImageHorLayout = TRUE;
			
			if(!m_Theme.GetThemeMargins(nPartID,0,TMT_SIZINGMARGINS,&m_mrgnBk))
				AfxThrowUserException();

			if(m_Theme.IsLunaTheme() && (m_nBkStyle==CBNBKGNDSTYLE_CAPTION || m_nBkStyle==CBNBKGNDSTYLE_CLOSE))
			{
				// Set the corners to the transparent color
				CBitmap* pBmp = CBitmap::FromHandle(m_hBmpBk);
				BITMAP bm;
				pBmp->GetBitmap(&bm);
				CDC dcBk;
				dcBk.CreateCompatibleDC(NULL);
				CBitmap* pOldBmp = dcBk.SelectObject(pBmp);
				if(m_fBkImageHorLayout)
				{
					CRect r(0,0,bm.bmWidth/8-1,bm.bmHeight-1);
					for(int i=0; i<8; i++)
					{
						dcBk.SetPixel(r.left,r.top,m_rgbBkTransparent);
						dcBk.SetPixel(r.right,r.top,m_rgbBkTransparent);
						dcBk.SetPixel(r.left,r.bottom,m_rgbBkTransparent);
						dcBk.SetPixel(r.right,r.bottom,m_rgbBkTransparent);
						r.OffsetRect(bm.bmWidth/8,0);
					}
				}
				else
				{
					CRect r(0,0,bm.bmWidth-1,bm.bmHeight/8-1);
					for(int i=0; i<8; i++)
					{
						dcBk.SetPixel(r.left,r.top,m_rgbBkTransparent);
						dcBk.SetPixel(r.right,r.top,m_rgbBkTransparent);
						dcBk.SetPixel(r.left,r.bottom,m_rgbBkTransparent);
						dcBk.SetPixel(r.right,r.bottom,m_rgbBkTransparent);
						r.OffsetRect(0,bm.bmHeight/8);
					}
				}
				dcBk.SelectObject(pOldBmp);
			}
		}
		{
			// glyph color
			int nGlyphType;
			if(!m_Theme.GetThemeEnumValue(nPartID,0,TMT_GLYPHTYPE,&nGlyphType))
				AfxThrowUserException();
			
			if(nGlyphType==GT_IMAGEGLYPH)
			{
				COLORREF rgbTransGlyph = RGB(255,0,255);
				if(!m_Theme.GetThemeColor(nPartID,0,TMT_GLYPHTRANSPARENTCOLOR,&rgbTransGlyph))
					AfxThrowUserException();
				WCHAR szSpinGlyphIconFilename[MAX_PATH];
				if(!m_Theme.GetThemeFilename(nPartID,0,nGlyphPropID,szSpinGlyphIconFilename,MAX_PATH))
					AfxThrowUserException();
				if(!(hBmpGlyph = m_Theme.LoadBitmap(szSpinGlyphIconFilename)))
					AfxThrowUserException();

				CBitmap* pBmp = CBitmap::FromHandle(hBmpGlyph);
				if(pBmp==NULL)
					AfxThrowUserException();
				pOldBmpGlyph = dcGlyph.SelectObject(pBmp);

				BITMAP bm;
				pBmp->GetBitmap(&bm);
				m_rgbGlyph[0] = rgbTransGlyph;
				m_rgbGlyph[1] = rgbTransGlyph;
				m_rgbGlyph[2] = rgbTransGlyph;
				m_rgbGlyph[3] = rgbTransGlyph;
				m_rgbGlyph[4] = rgbTransGlyph;
				m_rgbGlyph[5] = rgbTransGlyph;
				m_rgbGlyph[6] = rgbTransGlyph;
				m_rgbGlyph[7] = rgbTransGlyph;
				
				COLORGLYPH st;
				st.rgbTransGlyph = rgbTransGlyph;
				st.nWidth = bm.bmWidth;
				st.nHeight = bm.bmHeight;
				st.pDC = &dcGlyph;
				switch(m_nBkStyle)
				{
				case CBNBKGNDSTYLE_CAPTION:
				case CBNBKGNDSTYLE_CLOSE:
					{
						if(m_fBkImageHorLayout)
						{
							for(int i=0;i<bm.bmWidth;i++)
							{
								if(i<bm.bmWidth/8)
									GetGlyphColorHor(i,0,bm.bmWidth/8,0,st);
								else if(i<bm.bmWidth/4)
									GetGlyphColorHor(i,bm.bmWidth/8,bm.bmWidth/4,1,st);
								else if(i<3*bm.bmWidth/8)
									GetGlyphColorHor(i,bm.bmWidth/4,3*bm.bmWidth/8,2,st);
								else if(i<bm.bmWidth/2)
									GetGlyphColorHor(i,3*bm.bmWidth/8,bm.bmWidth/2,3,st);
								else if(i<5*bm.bmWidth/8)
									GetGlyphColorHor(i,bm.bmWidth/2,5*bm.bmWidth/8,4,st);
								else if(i<6*bm.bmWidth/8)
									GetGlyphColorHor(i,5*bm.bmWidth/8,6*bm.bmWidth/8,5,st);
								else if(i<7*bm.bmWidth/8)
									GetGlyphColorHor(i,6*bm.bmWidth/8,7*bm.bmWidth/8,6,st);
								else if(i<bm.bmWidth)
									GetGlyphColorHor(i,7*bm.bmWidth/8,bm.bmWidth,7,st);
							}
						}
						else
						{
							for(int i=0;i<bm.bmHeight;i++)
							{
								if(i<bm.bmHeight/8)
									GetGlyphColorVer(i,0,bm.bmHeight/8,0,st);
								else if(i<bm.bmHeight/4)
									GetGlyphColorVer(i,bm.bmHeight/8,bm.bmHeight/4,1,st);
								else if(i<3*bm.bmHeight/8)
									GetGlyphColorVer(i,bm.bmHeight/4,3*bm.bmHeight/8,2,st);
								else if(i<bm.bmHeight/2)
									GetGlyphColorVer(i,3*bm.bmHeight/8,bm.bmHeight/2,3,st);
								else if(i<5*bm.bmHeight/8)
									GetGlyphColorVer(i,bm.bmHeight/2,5*bm.bmHeight/8,4,st);
								else if(i<6*bm.bmHeight/8)
									GetGlyphColorVer(i,5*bm.bmHeight/8,6*bm.bmHeight/8,5,st);
								else if(i<7*bm.bmHeight/8)
									GetGlyphColorVer(i,6*bm.bmHeight/8,7*bm.bmHeight/8,6,st);
								else if(i<bm.bmHeight)
									GetGlyphColorVer(i,7*bm.bmHeight/8,bm.bmHeight,7,st);
							}
						}
					}
					break;
				default:
					{
						if(m_fBkImageHorLayout)
						{
							int nBnWidth = bm.bmWidth/m_nImageCount;
							int nBnOffset = nBnWidth*m_nImageOffset;
							for(int i=nBnOffset;i<nBnOffset+4*nBnWidth;i++)
							{
								if(i<nBnOffset+nBnWidth)
									GetGlyphColorHor(i,nBnOffset,nBnOffset+nBnWidth,0,st);
								else if(i<nBnOffset+2*nBnWidth)
									GetGlyphColorHor(i,nBnOffset+nBnWidth,nBnOffset+2*nBnWidth,1,st);
								else if(i<nBnOffset+3*nBnWidth)
									GetGlyphColorHor(i,nBnOffset+2*nBnWidth,nBnOffset+3*nBnWidth,2,st);
								else if(i<nBnOffset+4*nBnWidth)
									GetGlyphColorHor(i,nBnOffset+3*nBnWidth,nBnOffset+4*nBnWidth,3,st);
							}
						}
						else
						{
							int nBnHeight = bm.bmHeight/m_nImageCount;
							int nBnOffset = nBnHeight*m_nImageOffset;
							for(int i=nBnOffset;i<nBnOffset+4*nBnHeight;i++)
							{
								if(i<nBnOffset+nBnHeight)
									GetGlyphColorVer(i,nBnOffset,nBnOffset+nBnHeight,0,st);
								else if(i<nBnOffset+2*nBnHeight)
									GetGlyphColorVer(i,nBnOffset+nBnHeight,nBnOffset+2*nBnHeight,1,st);
								else if(i<nBnOffset+3*nBnHeight)
									GetGlyphColorVer(i,nBnOffset+2*nBnHeight,nBnOffset+3*nBnHeight,2,st);
								else if(i<nBnOffset+4*nBnHeight)
									GetGlyphColorVer(i,nBnOffset+3*nBnHeight,nBnOffset+4*nBnHeight,3,st);
							}
						}
					}
					break;
				}
				dcGlyph.SelectObject(pOldBmpGlyph);
				pOldBmpGlyph = NULL;
				::DeleteObject(hBmpGlyph);
				hBmpGlyph = NULL;
			}
			else
				AfxThrowUserException();
		}
	}
	catch(CUserException* e)
	{
		e->Delete();
		::DeleteObject(m_hBmpBk);
		m_hBmpBk = NULL;
		if(pOldBmpGlyph)
			dcGlyph.SelectObject(pOldBmpGlyph);
		::DeleteObject(hBmpGlyph);
		hBmpGlyph = NULL;
	}
	if(!(GetStyle()&CBNSTYLE_CAPTION))
		m_Theme.CloseThemeData();
	return 0;
}

void CCustomBitmapButton::PreSubclassWindow()
{
	OnThemeChanged(0,0);
	CWnd::PreSubclassWindow();
}

void CCustomBitmapButton::OnLButtonDown(UINT nFlags, CPoint point)
{
	CRect rCl;
	GetClientRect(&rCl);
	if(rCl.PtInRect(point))
	{
		SetCapture();
		m_nState = CBNST_PRESSED;
		m_bHeld = HELDLCLK;
		Invalidate(FALSE);
	}
	CWnd::OnLButtonDown(nFlags, point);
}

void CCustomBitmapButton::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	CRect rCl;
	GetClientRect(&rCl);
	if(rCl.PtInRect(point))
	{
		SetCapture();
		m_nState = CBNST_PRESSED;
		m_bHeld = HELDLDBLCLK;
		Invalidate(FALSE);
	}
	CWnd::OnLButtonDblClk(nFlags, point);
}

void CCustomBitmapButton::OnLButtonUp(UINT nFlags, CPoint point)
{
	if(m_bHeld==HELDLCLK || m_bHeld==HELDLDBLCLK)
	{
		CRect rCl;
		GetClientRect(&rCl);
		if(rCl.PtInRect(point))
		{
			NMHDR nmh;
			memset(&nmh,0,sizeof(NMHDR));
			nmh.hwndFrom = GetSafeHwnd();
			nmh.idFrom = GetDlgCtrlID();
			if(m_bHeld==HELDLCLK)
				nmh.code = NM_CLICK;
			else
				nmh.code = NM_DBLCLK;
			GetParent()->SendMessage(WM_NOTIFY,GetDlgCtrlID(),(LPARAM)&nmh);
			CPoint pt;
			::GetCursorPos(&pt);
			ScreenToClient(&pt);
			if(rCl.PtInRect(pt))
				m_nState = CBNST_HOT;
			else
				m_nState = CBNST_NORMAL;
		}
		m_bHeld = HELDNONE;
		ReleaseCapture();
		Invalidate(FALSE);
	}
	CWnd::OnLButtonUp(nFlags, point);
}

void CCustomBitmapButton::OnRButtonDown(UINT nFlags, CPoint point) 
{
	CRect rCl;
	GetClientRect(&rCl);
	if(rCl.PtInRect(point))
	{
		SetCapture();
		m_nState = CBNST_PRESSED;
		m_bHeld = HELDRCLK;
		Invalidate(FALSE);
	}
	CWnd::OnRButtonDown(nFlags, point);
}

void CCustomBitmapButton::OnRButtonDblClk(UINT nFlags, CPoint point) 
{
	CRect rCl;
	GetClientRect(&rCl);
	if(rCl.PtInRect(point))
	{
		SetCapture();
		m_nState = CBNST_PRESSED;
		m_bHeld = HELDRDBLCLK;
		Invalidate(FALSE);
	}
	CWnd::OnRButtonDblClk(nFlags, point);
}

void CCustomBitmapButton::OnRButtonUp(UINT nFlags, CPoint point) 
{	
	if(m_bHeld==HELDRCLK || m_bHeld==HELDRDBLCLK)
	{
		CRect rCl;
		GetClientRect(&rCl);
		if(rCl.PtInRect(point))
		{
			NMHDR nmh;
			memset(&nmh,0,sizeof(NMHDR));
			nmh.hwndFrom = GetSafeHwnd();
			nmh.idFrom = GetDlgCtrlID();
			if(m_bHeld==HELDRCLK)
				nmh.code = NM_RCLICK;
			else
				nmh.code = NM_RDBLCLK;
			GetParent()->SendMessage(WM_NOTIFY,GetDlgCtrlID(),(LPARAM)&nmh);
			CPoint pt;
			::GetCursorPos(&pt);
			ScreenToClient(&pt);
			if(rCl.PtInRect(pt))
				m_nState = CBNST_HOT;
			else
				m_nState = CBNST_NORMAL;
		}
		m_bHeld = HELDNONE;
		ReleaseCapture();
		Invalidate(FALSE);
	}
	CWnd::OnRButtonUp(nFlags, point);
}

LONG CCustomBitmapButton::OnMouseLeave(WPARAM wParam, LPARAM lParam) 
{
	m_nState = CBNST_NORMAL;
	Invalidate(FALSE);
	return 0;
}

void CCustomBitmapButton::OnMouseMove(UINT nFlags, CPoint point)
{
	TRACKMOUSEEVENT trackmouseevent;
	trackmouseevent.cbSize = sizeof(trackmouseevent);
	trackmouseevent.dwFlags = TME_LEAVE;
	trackmouseevent.hwndTrack = GetSafeHwnd();
	trackmouseevent.dwHoverTime = 0;
	_TrackMouseEvent(&trackmouseevent);

	CRect rCl;
	GetClientRect(&rCl);

	if(GetCapture()==this)
	{
		if(rCl.PtInRect(point))
			m_nState = CBNST_PRESSED;
		else
			m_nState = CBNST_NORMAL;
	}
	else
		m_nState = CBNST_HOT;
	Invalidate(FALSE);
	CWnd::OnMouseMove(nFlags, point);
}

void CCustomBitmapButton::Draw(CDC &dc)
{
	if(!m_hBmpBk)
	{
		m_rgbGlyph[0] = ::GetSysColor(COLOR_BTNTEXT);
		m_rgbGlyph[1] = ::GetSysColor(COLOR_BTNTEXT);
		m_rgbGlyph[2] = ::GetSysColor(COLOR_BTNTEXT);
		m_rgbGlyph[3] = ::GetSysColor(COLOR_GRAYTEXT);
		m_rgbGlyph[4] = ::GetSysColor(COLOR_BTNTEXT);
		m_rgbGlyph[5] = ::GetSysColor(COLOR_BTNTEXT);
		m_rgbGlyph[6] = ::GetSysColor(COLOR_BTNTEXT);
		m_rgbGlyph[7] = ::GetSysColor(COLOR_GRAYTEXT);
	}

	CRect r;
	CPoint pt(0,0);
	if(GetStyle()&CBNSTYLE_CAPTION)
	{
		r = m_rect;
		pt = r.TopLeft();
		r.OffsetRect(-pt.x,-pt.y);
	}
	else
		GetClientRect(&r);

	CDC dcMem;
	if(!dcMem.CreateCompatibleDC(&dc))
		return;
	if(m_bmpMemButton.m_hObject)
	{
		BITMAP bm;
		m_bmpMemButton.GetBitmap(&bm);
		if(bm.bmWidth!=r.Width() || bm.bmHeight!=r.Height())
		{
			m_bmpMemButton.DeleteObject();
			if(!m_bmpMemButton.CreateCompatibleBitmap(&dc,r.Width(),r.Height()))
				return;
		}
	}
	else
	{
		if(!m_bmpMemButton.CreateCompatibleBitmap(&dc,r.Width(),r.Height()))
			return;
	}

	CBitmap* pOldBmp = dcMem.SelectObject(&m_bmpMemButton);
	
	DWORD dwState = 0;

	if(IsWindowEnabled())
	{
		if(m_nState==CBNST_DISABLED)
			m_nState = CBNST_NORMAL;
		if(m_nState==CBNST_PRESSED)
			dwState=DFCS_PUSHED;
	}
	else 
	{
		dwState=DFCS_INACTIVE;
		m_nState=CBNST_DISABLED;
	}
	
	int nImageOffset=0;
	if(m_nBkStyle>=CBNBKGNDSTYLE_CAPTION && m_nBkStyle<=CBNBKGNDSTYLE_CLOSE && !m_fActive)
		nImageOffset = 4;

	int nState = m_nState-1;
	
	if(m_hBmpBk)
		DrawBk(dcMem,r,nState+nImageOffset+m_nImageOffset);
	else
		dcMem.DrawFrameControl(r,DFC_BUTTON,DFCS_BUTTONPUSH|dwState);
	DrawGlyph(dcMem,r,nState+nImageOffset);
	
	if(m_hBmpBk && m_fBkTransparent)
		m_Theme.TransparentBlt(dc.m_hDC,pt.x,pt.y,r.Width(),r.Height(),dcMem.m_hDC,0,0,r.Width(),r.Height(),m_rgbBkTransparent);
	else
		dc.BitBlt(pt.x,pt.y,r.Width(),r.Height(),&dcMem,r.left,r.top,SRCCOPY);
	dcMem.SelectObject(pOldBmp);
}

LRESULT CALLBACK CCustomBitmapButton::CaptionFrameWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	CCustomBitmapButton* p;
	m_cs.Lock();
	if(!m_mapCaptionFrames.Lookup(hWnd,p))
	{
		m_cs.Unlock();
		return 0;
	}
	m_cs.Unlock();
	
	CWnd* pWnd = CWnd::FromHandle(hWnd);
	switch(message)
	{
	case WM_SETTEXT:
		{
			CRect r;
			pWnd->GetWindowRect(r);
			r.OffsetRect(-r.left,-r.top);
			pWnd->RedrawWindow(r,NULL,RDW_FRAME|RDW_INVALIDATE);
		}
		break;
	case WM_GETMINMAXINFO:
		{
			LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam;
			CFont fn;
			int nCY, nPartID, nBtnsWidth;
			int nMinWidth = p->RecalcLayout(pWnd,nCY,nPartID,fn,nBtnsWidth);
			if(nMinWidth==-1 || nMinWidth > lpmmi->ptMinTrackSize.x)
				lpmmi->ptMinTrackSize.x = nMinWidth;
		}
		break;
	case WM_THEMECHANGED:
		{
			p->m_Theme.CloseThemeData();
			p->m_Theme.OpenThemeData(hWnd,L"WINDOW");
		}
		break;
	case WM_ACTIVATE:
		{
			p->m_fActive = LOWORD(wParam);
			for(int i=0; i<p->m_aButtons.GetSize(); i++)
				p->m_aButtons[i]->m_fActive = LOWORD(wParam);
			CRect r;
			pWnd->GetWindowRect(r);
			r.OffsetRect(-r.left,-r.top);
			pWnd->RedrawWindow(r,NULL,RDW_FRAME|RDW_INVALIDATE);
			if(pWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)))
			{
				CWnd* pActiveWnd = ((CMDIFrameWnd*)pWnd)->MDIGetActive();
				TRACE(_T("ACTIVE %p\n"),pActiveWnd);
				if(pActiveWnd!=NULL)
					pActiveWnd->PostMessage(WM_NCACTIVATE,LOWORD(wParam),0);
			}
			return 0;
		}
		break;
	case WM_NCACTIVATE:
		{
			if(pWnd->IsKindOf(RUNTIME_CLASS(CMDIChildWnd)))
			{
				p->m_fActive = wParam;
				for(int i=0; i<p->m_aButtons.GetSize(); i++)
					p->m_aButtons[i]->m_fActive = wParam;
				CRect r;
				pWnd->GetWindowRect(r);
				r.OffsetRect(-r.left,-r.top);
				pWnd->RedrawWindow(r,NULL,RDW_FRAME|RDW_INVALIDATE);
			}
			return TRUE;
		}
		break;
	case WM_NCPAINT:
		{
			if(p->m_Theme.IsThemeActive())
				p->DrawNCXP(pWnd);
			else
				p->DrawNCClasic(pWnd);
			if(p->m_ctrlToolTip.m_hWnd)
			{
				for(int i=4;i<p->m_aButtons.GetSize();i++)
				{
					if(p->m_aButtons[i]->m_rect.IsRectEmpty() || p->m_aButtons[i]->m_nState==CBNST_DISABLED)
						p->m_ctrlToolTip.SetToolRect(pWnd,p->m_aButtons[i]->GetDlgCtrlID(),CRect(0,0,0,0));
					else
					{
						CRect r = p->m_aButtons[i]->m_rect;
						CRect rW;
						pWnd->GetWindowRect(rW);
						CRect rC;
						pWnd->GetClientRect(rC);
						pWnd->ClientToScreen(rC);
						r.OffsetRect(rW.left-rC.left,rW.top-rC.top);
						p->m_ctrlToolTip.SetToolRect(pWnd,p->m_aButtons[i]->GetDlgCtrlID(),r);
					}
				}
			}
			return 0;
		}
		break;
	case WM_NCHITTEST:
		{
			CPoint pt(MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			CRect r;
			pWnd->GetWindowRect(r);
			pt.Offset(-r.left,-r.top);
			for(int i=0;i<p->m_aButtons.GetSize();i++)
			{
				if(p->m_aButtons[i]->m_rect.PtInRect(pt))
				{
					switch(i)
					{
					case 0:
						return HTCLOSE;
					case 1:
						return HTMAXBUTTON;
					case 2:
						return HTMINBUTTON;
					case 3:
						return HTHELP;
					default:
						return HTCAPTION;
					}
				}
			}
		}
		break;
	case WM_NCMOUSEMOVE:
		{
			TRACKMOUSEEVENT trackmouseevent;
			trackmouseevent.cbSize = sizeof(trackmouseevent);
			trackmouseevent.dwFlags = TME_NONCLIENT;
			trackmouseevent.hwndTrack = pWnd->GetSafeHwnd();
			trackmouseevent.dwHoverTime = 0;
			::_TrackMouseEvent(&trackmouseevent);

			CPoint pt(MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			CRect r;
			pWnd->GetWindowRect(r);
			pt.Offset(-r.left,-r.top);
			for(int i=0;i<p->m_aButtons.GetSize();i++)
			{
				if(p->m_aButtons[i]->m_rect.PtInRect(pt))
				{
					if(p->m_aButtons[i]->m_nState!=CBNST_DISABLED)
						p->m_aButtons[i]->m_nState = CBNST_HOT;
					pWnd->RedrawWindow(p->m_aButtons[i]->m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
					break;
				}
			}
			if(p->m_nOverNdx!=-1 && p->m_nOverNdx!=i)
			{
				if(p->m_aButtons[p->m_nOverNdx]->m_nState!=CBNST_DISABLED)
					p->m_aButtons[p->m_nOverNdx]->m_nState = CBNST_NORMAL;
				pWnd->RedrawWindow(p->m_aButtons[p->m_nOverNdx]->m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
			}
			if(i==p->m_aButtons.GetSize())
				p->m_nOverNdx=-1;
			else
				p->m_nOverNdx=i;
			if(p->m_ctrlToolTip.m_hWnd)
			{
				MSG msg;
				msg.lParam = lParam; 
                msg.wParam = wParam; 
                msg.message = message; 
                msg.hwnd = hWnd; 
                p->m_ctrlToolTip.RelayEvent(&msg); 
			}
			if(pWnd->IsIconic())
				return 0;
		}
		break;
	case WM_NCMOUSELEAVE:
		{	
			if(p->m_nOverNdx!=-1)
			{
				if(p->m_nHeldNdx!=-1)
					break;
				if(p->m_aButtons[p->m_nOverNdx]->m_nState!=CBNST_DISABLED)
					p->m_aButtons[p->m_nOverNdx]->m_nState = CBNST_NORMAL;
				pWnd->RedrawWindow(p->m_aButtons[p->m_nOverNdx]->m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
				p->m_nOverNdx = -1;
			}
		}
		break;
	case WM_MOUSEMOVE:
		{
			CPoint pt(MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			pWnd->ClientToScreen(&pt);
			CRect r;
			pWnd->GetWindowRect(r);
			pt.Offset(-r.left,-r.top);
			if(p->m_nHeldNdx!=-1)
			{
				if(p->m_aButtons[p->m_nHeldNdx]->m_nState!=CBNST_DISABLED)
				{
					if(p->m_aButtons[p->m_nHeldNdx]->m_rect.PtInRect(pt))
						p->m_aButtons[p->m_nHeldNdx]->m_nState = CBNST_PRESSED;
					else
						p->m_aButtons[p->m_nHeldNdx]->m_nState = CBNST_NORMAL;
				}
				pWnd->RedrawWindow(p->m_aButtons[p->m_nHeldNdx]->m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
			}
		}
		break;
	case WM_NCLBUTTONDOWN:
		{
			if(p->m_ctrlToolTip.m_hWnd)
			{
				MSG msg;
				msg.lParam = lParam; 
                msg.wParam = wParam; 
                msg.message = message; 
                msg.hwnd = hWnd; 
                p->m_ctrlToolTip.RelayEvent(&msg); 
			}
			CPoint pt(MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			CRect r;
			pWnd->GetWindowRect(r);
			pt.Offset(-r.left,-r.top);
			for(int i=0;i<p->m_aButtons.GetSize();i++)
			{
				if(p->m_aButtons[i]->m_rect.PtInRect(pt))
				{
					if(!p->m_fActive)
						pWnd->SetActiveWindow();
					if(p->m_aButtons[i]->m_nState!=CBNST_DISABLED)
					{
						pWnd->SetCapture();
						p->m_aButtons[i]->m_nState = CBNST_PRESSED;
						p->m_nHeldNdx = i;
						p->m_bHeld = HELDLCLK;
						pWnd->RedrawWindow(p->m_aButtons[i]->m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
					}
					return 0;
				}
			}
		}
		break;
	case WM_NCLBUTTONDBLCLK:
		{
			CPoint pt(MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			CRect r;
			pWnd->GetWindowRect(r);
			pt.Offset(-r.left,-r.top);
			for(int i=0;i<p->m_aButtons.GetSize();i++)
			{
				if(p->m_aButtons[i]->m_rect.PtInRect(pt))
				{
					if(p->m_aButtons[i]->m_nState!=CBNST_DISABLED)
					{
						pWnd->SetCapture();
						p->m_aButtons[i]->m_nState = CBNST_PRESSED;
						p->m_nHeldNdx = i;
						p->m_bHeld = HELDLDBLCLK;
						pWnd->RedrawWindow(p->m_aButtons[i]->m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
					}
					return 0;
				}
			}
		}
		break;
	case WM_NCRBUTTONDOWN:
		{
			CPoint pt(MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			CRect r;
			pWnd->GetWindowRect(r);
			pt.Offset(-r.left,-r.top);
			for(int i=0;i<p->m_aButtons.GetSize();i++)
			{
				if(p->m_aButtons[i]->m_rect.PtInRect(pt))
				{
					if(!p->m_fActive)
						pWnd->SetActiveWindow();
					if(p->m_aButtons[i]->m_nState!=CBNST_DISABLED)
					{
						pWnd->SetCapture();
						p->m_aButtons[i]->m_nState = CBNST_PRESSED;
						p->m_nHeldNdx = i;
						p->m_bHeld = HELDRCLK;
						pWnd->RedrawWindow(p->m_aButtons[i]->m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
					}
					return 0;
				}
			}
		}
		break;
	case WM_NCRBUTTONDBLCLK:
		{
			CPoint pt(MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			CRect r;
			pWnd->GetWindowRect(r);
			pt.Offset(-r.left,-r.top);
			for(int i=0;i<p->m_aButtons.GetSize();i++)
			{
				if(p->m_aButtons[i]->m_rect.PtInRect(pt))
				{
					if(p->m_aButtons[i]->m_nState!=CBNST_DISABLED)
					{
						pWnd->SetCapture();
						p->m_aButtons[i]->m_nState = CBNST_PRESSED;
						p->m_nHeldNdx = i;
						p->m_bHeld = HELDRDBLCLK;
						pWnd->RedrawWindow(p->m_aButtons[i]->m_rect,NULL,RDW_FRAME|RDW_INVALIDATE);
					}
					return 0;
				}
			}
		}
		break;
	case WM_LBUTTONUP:
		{
			if(p->m_ctrlToolTip.m_hWnd)
			{
				MSG msg;
				msg.lParam = lParam; 
                msg.wParam = wParam; 
                msg.message = message; 
                msg.hwnd = hWnd; 
                p->m_ctrlToolTip.RelayEvent(&msg); 
			}
			CPoint pt(MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			pWnd->ClientToScreen(&pt);
			CRect r;
			pWnd->GetWindowRect(r);
			pt.Offset(-r.left,-r.top);
			if(p->m_nHeldNdx!=-1 && (p->m_bHeld==HELDLCLK || p->m_bHeld==HELDLDBLCLK))
			{
				if(p->m_aButtons[p->m_nHeldNdx]->m_rect.PtInRect(pt) &&
					p->m_aButtons[p->m_nHeldNdx]->m_nState!=CBNST_DISABLED)
				{
					switch(p->m_nHeldNdx)
					{
					case 0:
						if(p->m_bHeld==HELDLCLK)
							pWnd->PostMessage(WM_SYSCOMMAND,SC_CLOSE,lParam);
						break;
					case 1:
						{
							if(p->m_bHeld==HELDLCLK)
							{
								if(pWnd->IsZoomed())
									pWnd->PostMessage(WM_SYSCOMMAND,SC_RESTORE,lParam);
								else
									pWnd->PostMessage(WM_SYSCOMMAND,SC_MAXIMIZE,lParam);
							}
						}
						break;
					case 2:
						{
							if(p->m_bHeld==HELDLCLK)
							{
								if(pWnd->IsIconic())
									pWnd->PostMessage(WM_SYSCOMMAND,SC_RESTORE,lParam);
								else
									pWnd->PostMessage(WM_SYSCOMMAND,SC_MINIMIZE,lParam);
							}
						}
						break;
					case 3:
						if(p->m_bHeld==HELDLCLK)
							pWnd->PostMessage(WM_SYSCOMMAND,SC_CONTEXTHELP,lParam);
						break;
					default:
						{
							NMHDR nmh;
							memset(&nmh,0,sizeof(NMHDR));
							nmh.hwndFrom = p->m_aButtons[p->m_nHeldNdx]->GetSafeHwnd();
							nmh.idFrom = p->m_aButtons[p->m_nHeldNdx]->GetDlgCtrlID();
							if(p->m_bHeld==HELDLCLK)
								nmh.code = NM_CLICK;
							else
								nmh.code = NM_DBLCLK;
							pWnd->SendMessage(WM_NOTIFY,p->m_aButtons[p->m_nHeldNdx]->GetDlgCtrlID(),(LPARAM)&nmh);
						}
						break;
					}
				}
				p->m_nHeldNdx = -1;
				p->m_bHeld = HELDNONE;
				::ReleaseCapture();
				pt.Offset(r.TopLeft());
				pWnd->PostMessage(WM_NCMOUSEMOVE,HTCAPTION,MAKELPARAM(pt.x,pt.y));
				return 0;
			}
		}
		break;
	case WM_RBUTTONUP:
		{
			CPoint pt(MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
			pWnd->ClientToScreen(&pt);
			CRect r;
			pWnd->GetWindowRect(r);
			pt.Offset(-r.left,-r.top);
			if(p->m_nHeldNdx!=-1 && (p->m_bHeld==HELDRCLK || p->m_bHeld==HELDRDBLCLK))
			{
				if(p->m_aButtons[p->m_nHeldNdx]->m_rect.PtInRect(pt) && 
					p->m_aButtons[p->m_nHeldNdx]->m_nState!=CBNST_DISABLED)
				{
					NMHDR nmh;
					memset(&nmh,0,sizeof(NMHDR));
					nmh.hwndFrom = p->m_aButtons[p->m_nHeldNdx]->GetSafeHwnd();
					nmh.idFrom = p->m_aButtons[p->m_nHeldNdx]->GetDlgCtrlID();
					if(p->m_bHeld==HELDRCLK)
						nmh.code = NM_RCLICK;
					else
						nmh.code = NM_RDBLCLK;
					pWnd->SendMessage(WM_NOTIFY,p->m_aButtons[p->m_nHeldNdx]->GetDlgCtrlID(),(LPARAM)&nmh);
				}
				p->m_nHeldNdx = -1;
				p->m_bHeld = HELDNONE;
				::ReleaseCapture();
				pt.Offset(r.TopLeft());
				pWnd->PostMessage(WM_NCMOUSEMOVE,HTCAPTION,MAKELPARAM(pt.x,pt.y));
				return 0;
			}
		}
		break;
	}
	
	if(message==174)
		return 0;

	return ::CallWindowProc(p->m_pOldWndProc, hWnd, message, wParam, lParam);
}

int CCustomBitmapButton::RecalcLayout(CWnd *pWnd, int& nCY, int& nPartID, CFont& fn, int& nBtnsWidth)
{
	CRect rect;
	LONG dwStyle = pWnd->GetStyle();
	pWnd->GetWindowRect(&rect);

	NONCLIENTMETRICS ncm;
	ncm.cbSize = sizeof(NONCLIENTMETRICS);
	SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm,0);	 

	CSize sizeIcon(::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON));
	CSize sizeBtns;
	CSize sizeFrame(::GetSystemMetrics(SM_CXDLGFRAME),::GetSystemMetrics(SM_CYDLGFRAME));
	if(dwStyle&WS_THICKFRAME)
	{
		sizeFrame.cx = ::GetSystemMetrics(SM_CXFRAME);
		sizeFrame.cy = ::GetSystemMetrics(SM_CYFRAME);
	}

	BOOL fA = m_Theme.IsThemeActive();

	if(pWnd->GetExStyle()&WS_EX_TOOLWINDOW)
	{
		if(!fn.CreateFontIndirect(&ncm.lfSmCaptionFont))
			return -1;
		nCY = ::GetSystemMetrics(SM_CYSMCAPTION);
		nPartID = WP_SMALLCAPTION;
		if(fA)
		{
			sizeBtns.cx = ::GetSystemMetrics(SM_CXSMSIZE)-4;
			sizeBtns.cy = ::GetSystemMetrics(SM_CYSMSIZE)-4;
		}
		else
		{
			sizeBtns.cx = ::GetSystemMetrics(SM_CXSMSIZE)-2;
			sizeBtns.cy = ::GetSystemMetrics(SM_CYSMSIZE)-4;
		}
	}
	else
	{
		if(!fn.CreateFontIndirect(&ncm.lfCaptionFont))
			return -1;
		nCY = ::GetSystemMetrics(SM_CYCAPTION);
		nPartID = WP_CAPTION;
		if(fA)
		{
			sizeBtns.cx = ::GetSystemMetrics(SM_CXSIZE)-4;
			sizeBtns.cy = ::GetSystemMetrics(SM_CYSIZE)-4;
		}
		else
		{
			sizeBtns.cx = ::GetSystemMetrics(SM_CXSIZE)-2;
			sizeBtns.cy = ::GetSystemMetrics(SM_CYSIZE)-4;
		}
	}

	CRect rectCaption;
	if(fA)
	{
		nBtnsWidth=sizeFrame.cx;
		rectCaption.SetRect(0,0,rect.Width(),nCY+sizeFrame.cy);
	}
	else
	{
		rectCaption.SetRect(0,0,rect.Width(),nCY-1+sizeFrame.cy);
		rectCaption.InflateRect(-sizeFrame.cx, 0);
		rectCaption.top += sizeFrame.cy;
		nBtnsWidth=0;
	}

	if (dwStyle & WS_SYSMENU)
	{
		m_aButtons[0]->m_rect.SetRect(0,0,sizeBtns.cx,sizeBtns.cy);
		nBtnsWidth += m_aButtons[0]->m_rect.Width() + 2;
		m_aButtons[0]->m_rect.OffsetRect(rectCaption.Width()-nBtnsWidth,fA ? 2+sizeFrame.cy : 2);
		if (dwStyle&WS_MAXIMIZEBOX || dwStyle&WS_MINIMIZEBOX)
		{
			m_aButtons[1]->m_rect.SetRect(0,0,sizeBtns.cx,sizeBtns.cy);
			nBtnsWidth += m_aButtons[1]->m_rect.Width() + 2;
			m_aButtons[1]->m_rect.OffsetRect(rectCaption.Width()-nBtnsWidth,fA ? 2+sizeFrame.cy : 2);
			if(!(dwStyle&WS_MAXIMIZEBOX))
				m_aButtons[1]->m_nState = CBNST_DISABLED;
			else if(m_aButtons[1]->m_nState==CBNST_DISABLED)
				m_aButtons[1]->m_nState = CBNST_NORMAL;
			m_aButtons[2]->m_rect.SetRect(0,0,sizeBtns.cx,sizeBtns.cy);
			if(fA)
				nBtnsWidth += m_aButtons[2]->m_rect.Width() + 2;
			else
				nBtnsWidth += m_aButtons[2]->m_rect.Width();
			m_aButtons[2]->m_rect.OffsetRect(rectCaption.Width()-nBtnsWidth ,fA ? 2+sizeFrame.cy : 2);
			if(!(dwStyle&WS_MINIMIZEBOX))
				m_aButtons[2]->m_nState = CBNST_DISABLED;
			else if(m_aButtons[2]->m_nState==CBNST_DISABLED)
				m_aButtons[2]->m_nState = CBNST_NORMAL;
			m_aButtons[3]->m_rect.SetRectEmpty();
		}
		else if(pWnd->GetExStyle()&WS_EX_CONTEXTHELP)
		{
			m_aButtons[1]->m_rect.SetRectEmpty();
			m_aButtons[2]->m_rect.SetRectEmpty();
			m_aButtons[3]->m_rect.SetRect(0,0,sizeBtns.cx,sizeBtns.cy);
			nBtnsWidth += m_aButtons[3]->m_rect.Width() + 2;
			m_aButtons[3]->m_rect.OffsetRect(rectCaption.Width()-nBtnsWidth,fA ? 2+sizeFrame.cy : 2);
		}
		else
		{
			m_aButtons[1]->m_rect.SetRectEmpty();
			m_aButtons[2]->m_rect.SetRectEmpty();
			m_aButtons[3]->m_rect.SetRectEmpty();
		}
	}
	else
	{
		m_aButtons[0]->m_rect.SetRectEmpty();
		m_aButtons[1]->m_rect.SetRectEmpty();
		m_aButtons[2]->m_rect.SetRectEmpty();
		m_aButtons[3]->m_rect.SetRectEmpty();
	}
	
	for(int i=4; i<m_aButtons.GetSize(); i++)
	{
		if(pWnd->IsIconic())
		{
			m_aButtons[i]->m_rect.top = 0;
			m_aButtons[i]->m_rect.bottom = 0;
		}
		else
		{
			if(m_aButtons[i]->GetStyle()&CBNSTYLE_USERDEFWIDTH)
				m_aButtons[i]->m_rect.SetRect(0,0,m_aButtons[i]->m_rect.Width(),sizeBtns.cy);
			else
				m_aButtons[i]->m_rect.SetRect(0,0,sizeBtns.cx,sizeBtns.cy);
			nBtnsWidth += m_aButtons[i]->m_rect.Width() + 2;
			m_aButtons[i]->m_rect.OffsetRect(rectCaption.Width()-nBtnsWidth,fA ? 2+sizeFrame.cy : 2);
		}
	}

	CWindowDC dc(pWnd);
	CFont* pFontOld = dc.SelectObject(&fn);
	CRect r;
	dc.DrawText(_T("W..."),r,DT_CALCRECT|DT_SINGLELINE);
	dc.SelectObject(pFontOld);
	return sizeFrame.cx + (dwStyle & WS_SYSMENU ? sizeIcon.cx+6 : 4) + r.Width() + nBtnsWidth;
}

void CCustomBitmapButton::DrawNCClasic(CWnd* pWnd)
{
	CWindowDC dc(pWnd);
	LONG dwStyle = pWnd->GetStyle();
	CRect rWnd;
	pWnd->GetWindowRect(&rWnd);
	CSize sizeIcon(::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON));

	CSize sizeFrame(::GetSystemMetrics(SM_CXDLGFRAME),::GetSystemMetrics(SM_CYDLGFRAME));
	if(dwStyle&WS_THICKFRAME)
	{
		sizeFrame.cx = ::GetSystemMetrics(SM_CXFRAME);
		sizeFrame.cy = ::GetSystemMetrics(SM_CYFRAME);
	}

	CFont fn;
	int nCY, nPartID, nBtnsWidth;

	if(RecalcLayout(pWnd,nCY,nPartID,fn,nBtnsWidth)==-1)
		return;

	CRect rCaption(0,0,rWnd.Width(),nCY-1+sizeFrame.cy);
	rCaption.InflateRect(-sizeFrame.cx, 0);
	rCaption.top += sizeFrame.cy;

	CRgn rgn1;
	rgn1.CreateRectRgn(rWnd.left,rWnd.top,rWnd.right,rWnd.bottom);
	CRgn rgn2;
	rgn2.CreateRectRgn(rWnd.left+rCaption.left,rWnd.top+rCaption.top,rWnd.left+rCaption.right,rWnd.top+rCaption.bottom);
	CRgn rgn;
	rgn.CreateRectRgn(0,0,0,0);
	rgn.CombineRgn(&rgn1,&rgn2,RGN_DIFF);
	::DefWindowProc(pWnd->m_hWnd,WM_NCPAINT,(WPARAM)rgn.m_hObject,0);

	rWnd.OffsetRect(-rWnd.left, -rWnd.top);

	CPoint ptOffset(rCaption.left,rCaption.top);
	rCaption.OffsetRect(-ptOffset.x, -ptOffset.y);

	CBrush brCaption;
	brCaption.CreateSolidBrush(::GetSysColor(m_fActive ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
	COLORREF rgbFrom = ::GetSysColor(m_fActive ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
	COLORREF rgbTo = ::GetSysColor(m_fActive ? COLOR_GRADIENTACTIVECAPTION : COLOR_GRADIENTINACTIVECAPTION);

	// Draw the caption
	CDC dcMem;
	dcMem.CreateCompatibleDC(&dc);

	if(m_bmpMemCaption.m_hObject)
	{
		BITMAP bm;
		m_bmpMemCaption.GetBitmap(&bm);
		if(bm.bmWidth!=rCaption.Width() || bm.bmHeight!=rCaption.Height())
		{
			m_bmpMemCaption.DeleteObject();
			if(!m_bmpMemCaption.CreateCompatibleBitmap(&dc,rCaption.Width(),rCaption.Height()))
				return;
		}
	}
	else
	{
		if(!m_bmpMemCaption.CreateCompatibleBitmap(&dc,rCaption.Width(),rCaption.Height()))
			return;
	}
	
	CBitmap* pOldBmp = dcMem.SelectObject(&m_bmpMemCaption);

	BOOL fRet = FALSE;
	::SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &fRet,0);

	if(fRet)
	{
		TRIVERTEX        vert[2] ;
		GRADIENT_RECT    gRect;

		vert[0] .x      = rCaption.left;
		vert[0] .y      = rCaption.top;
		vert[0] .Red    = GetRValue(rgbFrom)<<8;
		vert[0] .Green  = GetGValue(rgbFrom)<<8;
		vert[0] .Blue   = GetBValue(rgbFrom)<<8;
		vert[0] .Alpha  = 0x0000;

		vert[1] .x      = rCaption.right - nBtnsWidth;
		vert[1] .y      = rCaption.bottom; 
		vert[1] .Red    = GetRValue(rgbTo)<<8;
		vert[1] .Green  = GetGValue(rgbTo)<<8;
		vert[1] .Blue   = GetBValue(rgbTo)<<8;
		vert[1] .Alpha  = 0x0000;

		gRect.UpperLeft  = 0;
		gRect.LowerRight = 1;

		m_Theme.GradientFill(dcMem.m_hDC,vert,2,&gRect,1,GRADIENT_FILL_RECT_H);
		dcMem.FillSolidRect(rCaption.right - nBtnsWidth,rCaption.top,nBtnsWidth,rCaption.Height(),rgbTo);
	}
	else
		dcMem.FillRect(&rCaption, &brCaption);

	// Draw the system menu.
	if (dwStyle & WS_SYSMENU)
	{
		HICON hIcon = ::AfxGetApp()->LoadIcon(m_nIDIcon);
		if(hIcon!=NULL)
			::DrawIconEx(dcMem.m_hDC,2,(rCaption.Height()-sizeIcon.cy)/2,hIcon,sizeIcon.cx,sizeIcon.cy,0,NULL,DI_NORMAL);
	}

	// Draw the buttons
	
	for(int i=0; i<m_aButtons.GetSize(); i++)
	{
		if(!m_aButtons[i]->m_rect.IsRectEmpty())
		{
			DWORD dwState = 0;
			if(m_aButtons[i]->m_nState==CBNST_DISABLED)
				dwState=DFCS_INACTIVE;
			else if(m_aButtons[i]->m_nState==CBNST_PRESSED)
				dwState=DFCS_PUSHED;
			switch(i)
			{
			case 0:
				dcMem.DrawFrameControl(m_aButtons[i]->m_rect,DFC_CAPTION,DFCS_CAPTIONCLOSE|dwState);
				break;
			case 1:
				{
					if(pWnd->IsZoomed())
						dcMem.DrawFrameControl(m_aButtons[i]->m_rect,DFC_CAPTION,DFCS_CAPTIONRESTORE|dwState);
					else
						dcMem.DrawFrameControl(m_aButtons[i]->m_rect,DFC_CAPTION,DFCS_CAPTIONMAX|dwState);
				}
				break;
			case 2:
				{
					if(pWnd->IsIconic())
						dcMem.DrawFrameControl(m_aButtons[i]->m_rect,DFC_CAPTION,DFCS_CAPTIONRESTORE|dwState);
					else
						dcMem.DrawFrameControl(m_aButtons[i]->m_rect,DFC_CAPTION,DFCS_CAPTIONMIN|dwState);
				}
				break;
			case 3:
				dcMem.DrawFrameControl(m_aButtons[i]->m_rect,DFC_CAPTION,DFCS_CAPTIONHELP|dwState);
				break;
			default:
				m_aButtons[i]->Draw(dcMem);
				break;
			}
		}
	}

	// Draw the caption text

	CFont* pFontOld = dcMem.SelectObject(&fn);

	CString strTitle;
	pWnd->GetWindowText(strTitle);
	int xLeft = rCaption.left + 4 + (dwStyle & WS_SYSMENU ? sizeIcon.cx : 0);

	COLORREF rgbOldTxtColor = dcMem.SetTextColor(::GetSysColor(m_fActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
	int nOldBkMode = dcMem.SetBkMode(TRANSPARENT);
	UINT uFormat = DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS;
	if(pWnd->GetExStyle()&WS_EX_RIGHT)
		uFormat |= DT_RIGHT;
	dcMem.DrawText(strTitle,CRect(xLeft,0,rCaption.right-nBtnsWidth-2,rCaption.bottom),uFormat);
	dcMem.SetBkMode(nOldBkMode);
	dcMem.SetTextColor(rgbOldTxtColor);
	dcMem.SelectObject(pFontOld);

	dc.BitBlt(ptOffset.x,ptOffset.y,rCaption.Width(),rCaption.Height(),&dcMem,0,0,SRCCOPY);
	dcMem.SelectObject(pOldBmp);
	for(i=0; i<m_aButtons.GetSize(); i++)
	{
		if(!m_aButtons[i]->m_rect.IsRectEmpty())
			m_aButtons[i]->m_rect.OffsetRect(sizeFrame);
	}
}

void CCustomBitmapButton::DrawNCXP(CWnd* pWnd)
{
	CWindowDC dc(pWnd);
	LONG dwStyle = pWnd->GetStyle();
	CRect rWnd;
	pWnd->GetWindowRect(&rWnd);
	CSize sizeIcon(::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON));

	CSize sizeFrame(::GetSystemMetrics(SM_CXDLGFRAME),::GetSystemMetrics(SM_CYDLGFRAME));
	if(dwStyle&WS_THICKFRAME)
	{
		sizeFrame.cx = ::GetSystemMetrics(SM_CXFRAME);
		sizeFrame.cy = ::GetSystemMetrics(SM_CYFRAME);
	}

	CFont fn;
	int nCY, nPartID, nBtnsWidth;

	if(RecalcLayout(pWnd,nCY,nPartID,fn,nBtnsWidth)==-1)
		return;

	int nFrameState = FS_INACTIVE;
	if(m_fActive)
		nFrameState = FS_ACTIVE;

	CRect rCaption(0,0,rWnd.Width(),nCY+sizeFrame.cy);

	CRect rDef(rWnd.left+sizeFrame.cx,rWnd.top+rCaption.Height(),rWnd.right-sizeFrame.cx,rWnd.bottom-sizeFrame.cy);
	CRgn rgn;
	rgn.CreateRectRgn(rDef.left,rDef.top,rDef.right,rDef.bottom);

	::DefWindowProc(pWnd->m_hWnd,WM_NCPAINT,(WPARAM)rgn.m_hObject,0);
	
	rWnd.OffsetRect(-rWnd.left, -rWnd.top);
	
	CRect rLeftFrm(rWnd.left,rWnd.top+rCaption.Height(),rWnd.left+sizeFrame.cx,rWnd.bottom);
	CRect rRightFrm(rWnd.right-sizeFrame.cx,rWnd.top+rCaption.Height(),rWnd.right,rWnd.bottom);
	CRect rBottomFrm(rWnd.left,rWnd.bottom-sizeFrame.cy,rWnd.right,rWnd.bottom);
	if(pWnd->GetExStyle()&WS_EX_TOOLWINDOW)
	{
		m_Theme.DrawThemePart(dc.m_hDC,WP_SMALLFRAMELEFT,nFrameState,rLeftFrm);
		m_Theme.DrawThemePart(dc.m_hDC,WP_SMALLFRAMERIGHT,nFrameState,rRightFrm);
		m_Theme.DrawThemePart(dc.m_hDC,WP_SMALLFRAMEBOTTOM,nFrameState,rBottomFrm);
	}
	else
	{
		m_Theme.DrawThemePart(dc.m_hDC,WP_FRAMELEFT,nFrameState,rLeftFrm);
		m_Theme.DrawThemePart(dc.m_hDC,WP_FRAMERIGHT,nFrameState,rRightFrm);
		m_Theme.DrawThemePart(dc.m_hDC,WP_FRAMEBOTTOM,nFrameState,rBottomFrm);
	}

	// Draw the caption
	CDC dcMem;
	dcMem.CreateCompatibleDC(&dc);

	if(m_bmpMemCaption.m_hObject)
	{
		BITMAP bm;
		m_bmpMemCaption.GetBitmap(&bm);
		if(bm.bmWidth!=rCaption.Width() || bm.bmHeight!=rCaption.Height())
		{
			m_bmpMemCaption.DeleteObject();
			if(!m_bmpMemCaption.CreateCompatibleBitmap(&dc,rCaption.Width(),rCaption.Height()))
				return;
		}
	}
	else
	{
		if(!m_bmpMemCaption.CreateCompatibleBitmap(&dc,rCaption.Width(),rCaption.Height()))
			return;
	}
	
	CBitmap* pOldBmp = dcMem.SelectObject(&m_bmpMemCaption);

	m_Theme.DrawThemePart(dcMem.m_hDC,nPartID,nFrameState,rCaption);

	// Draw the system menu.
	if (dwStyle & WS_SYSMENU)
	{
		HICON hIcon = ::AfxGetApp()->LoadIcon(m_nIDIcon);
		if(hIcon!=NULL)
			::DrawIconEx(dcMem.m_hDC,2+sizeFrame.cx,sizeFrame.cy-1+(rCaption.Height()-sizeIcon.cy-sizeFrame.cy)/2,hIcon,sizeIcon.cx,sizeIcon.cy,0,NULL,DI_NORMAL);
	}

	// Draw the buttons
	for(int i=0; i<m_aButtons.GetSize(); i++)
	{
		if(!m_aButtons[i]->m_rect.IsRectEmpty())
		{
			int nStateOffset = 4;
			if(m_aButtons[i]->m_fActive)
				nStateOffset = 0;
			switch(i)
			{
			case 0:
				m_Theme.DrawThemePart(dcMem.m_hDC,WP_CLOSEBUTTON,m_aButtons[i]->m_nState+nStateOffset,m_aButtons[i]->m_rect);
				break;
			case 1:
				{
					if(pWnd->IsZoomed())
						m_Theme.DrawThemePart(dcMem.m_hDC,WP_RESTOREBUTTON,m_aButtons[i]->m_nState+nStateOffset,m_aButtons[i]->m_rect);
					else
						m_Theme.DrawThemePart(dcMem.m_hDC,WP_MAXBUTTON,m_aButtons[i]->m_nState+nStateOffset,m_aButtons[i]->m_rect);
				}
				break;
			case 2:
				{
					if(pWnd->IsIconic())
						m_Theme.DrawThemePart(dcMem.m_hDC,WP_RESTOREBUTTON,m_aButtons[i]->m_nState+nStateOffset,m_aButtons[i]->m_rect);
					else
						m_Theme.DrawThemePart(dcMem.m_hDC,WP_MINBUTTON,m_aButtons[i]->m_nState+nStateOffset,m_aButtons[i]->m_rect);
				}
				break;
			case 3:
				m_Theme.DrawThemePart(dcMem.m_hDC,WP_HELPBUTTON,m_aButtons[i]->m_nState+nStateOffset,m_aButtons[i]->m_rect);
				break;
			default:
				m_aButtons[i]->Draw(dcMem);
				break;
			}
		}
	}

	// Draw the caption text
	
	TCHAR strTitle[512];
	pWnd->GetWindowText(strTitle,512);
	int nTextXPos = sizeFrame.cx + (dwStyle & WS_SYSMENU ? sizeIcon.cx+6 : 4);

	CPoint ptShadow(0,0);
	m_Theme.GetThemePosition(nPartID,nFrameState,TMT_TEXTSHADOWOFFSET,&ptShadow);
		
	COLORREF rgbTxtShadowColor;
	COLORREF rgbTxtColor = ::GetSysColor(m_fActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
	m_Theme.GetThemeColor(nPartID,nFrameState,TMT_TEXTSHADOWCOLOR,&rgbTxtShadowColor);
	m_Theme.GetThemeColor(nPartID,nFrameState,TMT_CAPTIONTEXT,&rgbTxtColor);
	COLORREF rgbOldTxtColor = dcMem.SetTextColor(rgbTxtShadowColor);

	CFont* pFontOld = dcMem.SelectObject(&fn);
	int nOldBkMode = dcMem.SetBkMode(TRANSPARENT);
	CRect rTxt(nTextXPos+ptShadow.x,sizeFrame.cy+ptShadow.y,rCaption.right-nBtnsWidth-2,rCaption.Height()+ptShadow.y);
	UINT uFormat = DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS;
	if(pWnd->GetExStyle()&WS_EX_RIGHT)
		uFormat |= DT_RIGHT;
	if(ptShadow!=CPoint(0,0))
		dcMem.DrawText(strTitle,rTxt,uFormat);
	dcMem.SetTextColor(rgbTxtColor);
	rTxt.OffsetRect(-ptShadow.x,-ptShadow.y);
	dcMem.DrawText(strTitle,rTxt,uFormat);
	dcMem.SetBkMode(nOldBkMode);
	dcMem.SetTextColor(rgbOldTxtColor);
	dcMem.SelectObject(pFontOld);

	dc.BitBlt(0,0,rCaption.Width(),rCaption.Height(),&dcMem,0,0,SRCCOPY);
	dcMem.SelectObject(pOldBmp);
}

CCustomBitmapButton* CCustomBitmapButton::GetCaptionButtonPtr(int nButtonID)
{
	if(!m_pOldWndProc)
		return NULL;
	for(int i=4;i<m_aButtons.GetSize();i++)
	{
		if(m_aButtons[i]->GetDlgCtrlID()==nButtonID)
			return m_aButtons[i];
	}
	return NULL;
}

BOOL CCustomBitmapButton::PreTranslateMessage(MSG* pMsg) 
{
	if(m_ctrlToolTip.m_hWnd && 
		(pMsg->message==WM_LBUTTONDOWN || pMsg->message==WM_LBUTTONUP || pMsg->message==WM_MOUSEMOVE))
			m_ctrlToolTip.RelayEvent(pMsg);	
	return CWnd::PreTranslateMessage(pMsg);
}